/*
 * Copyright (c) 2011-2014, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package boofcv.alg.filter.convolve.noborder;

import boofcv.struct.image.*;

/**
 * <p>
 * Convolves a box filter across an image.  A box filter is equivalent to convolving a kernel with all 1's.
 * </p>
 * <p>
 * Do not modify.  Auto generated by {@link GenerateImplConvolveBox}.
 * </p>
 * 
 * @author Peter Abeles
 */
public class ImplConvolveBox {

	public static void horizontal( ImageUInt8 input , ImageInt16 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			int total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] & 0xFF;
			}
			output.data[indexOut++] = (short)total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] & 0xFF;
				total += input.data[ indexIn ] & 0xFF;

				output.data[indexOut++] = (short)total;
			}
		}
	}

	public static void vertical( ImageUInt8 input , ImageInt16 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			int total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] & 0xFF;
			}

			output.data[indexOut] = (short)total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				int total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]& 0xFF);
				total += input.data[ indexIn ]& 0xFF;

				output.data[indexOut] = (short)total;
			}
		}
	}

	public static void horizontal( ImageUInt8 input , ImageSInt32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			int total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] & 0xFF;
			}
			output.data[indexOut++] = total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] & 0xFF;
				total += input.data[ indexIn ] & 0xFF;

				output.data[indexOut++] = total;
			}
		}
	}

	public static void vertical( ImageUInt8 input , ImageSInt32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			int total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] & 0xFF;
			}

			output.data[indexOut] = total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				int total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]& 0xFF);
				total += input.data[ indexIn ]& 0xFF;

				output.data[indexOut] = total;
			}
		}
	}

	public static void horizontal( ImageSInt16 input , ImageInt16 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			int total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] ;
			}
			output.data[indexOut++] = (short)total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] ;
				total += input.data[ indexIn ] ;

				output.data[indexOut++] = (short)total;
			}
		}
	}

	public static void vertical( ImageSInt16 input , ImageInt16 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			int total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] ;
			}

			output.data[indexOut] = (short)total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				int total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]);
				total += input.data[ indexIn ];

				output.data[indexOut] = (short)total;
			}
		}
	}

	public static void horizontal( ImageSInt32 input , ImageSInt32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			int total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] ;
			}
			output.data[indexOut++] = total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] ;
				total += input.data[ indexIn ] ;

				output.data[indexOut++] = total;
			}
		}
	}

	public static void vertical( ImageSInt32 input , ImageSInt32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			int total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] ;
			}

			output.data[indexOut] = total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				int total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]);
				total += input.data[ indexIn ];

				output.data[indexOut] = total;
			}
		}
	}

	public static void horizontal( ImageFloat32 input , ImageFloat32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			float total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] ;
			}
			output.data[indexOut++] = total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] ;
				total += input.data[ indexIn ] ;

				output.data[indexOut++] = total;
			}
		}
	}

	public static void vertical( ImageFloat32 input , ImageFloat32 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			float total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] ;
			}

			output.data[indexOut] = total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				float total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]);
				total += input.data[ indexIn ];

				output.data[indexOut] = total;
			}
		}
	}

	public static void horizontal( ImageFloat64 input , ImageFloat64 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		for( int y = 0; y < input.height; y++ ) {
			int indexIn = input.startIndex + input.stride*y;
			int indexOut = output.startIndex + output.stride*y + radius;

			double total = 0;

			int indexEnd = indexIn + kernelWidth;
			
			for( ; indexIn < indexEnd; indexIn++ ) {
				total += input.data[indexIn] ;
			}
			output.data[indexOut++] = total;

			indexEnd = indexIn + input.width - kernelWidth;
			for( ; indexIn < indexEnd; indexIn++ ) {
				total -= input.data[ indexIn - kernelWidth ] ;
				total += input.data[ indexIn ] ;

				output.data[indexOut++] = total;
			}
		}
	}

	public static void vertical( ImageFloat64 input , ImageFloat64 output , int radius ) {
		final int kernelWidth = radius*2 + 1;

		final int backStep = kernelWidth*input.stride;

		for( int x = 0; x < input.width; x++ ) {
			int indexIn = input.startIndex + x;
			int indexOut = output.startIndex + output.stride*radius + x;

			double total = 0;
			int indexEnd = indexIn + input.stride*kernelWidth;
			for( ; indexIn < indexEnd; indexIn += input.stride) {
				total += input.data[indexIn] ;
			}

			output.data[indexOut] = total;
		}

		// change the order it is processed in to reduce cache misses
		for( int y = radius+1; y < output.height-radius; y++ ) {
			int indexIn = input.startIndex + (y+radius)*input.stride;
			int indexOut = output.startIndex + y*output.stride;

			for( int x = 0; x < input.width; x++ ,indexIn++,indexOut++) {
				double total = output.data[ indexOut - output.stride]  - (input.data[ indexIn - backStep ]);
				total += input.data[ indexIn ];

				output.data[indexOut] = total;
			}
		}
	}

}
